package Netty_impro;

import io.netty.bootstrap.Bootstrap;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.*;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.SocketChannel;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import io.netty.channel.socket.nio.NioSocketChannel;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;
import io.netty.handler.logging.LogLevel;
import io.netty.handler.logging.LoggingHandler;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import jdk.jfr.events.SocketReadEvent;

//验证黏包，半包现象
public class Server {
    public static void main(String[] args) throws InterruptedException {
        test2();
    }
    //验证黏包
    /*
         +-------------------------------------------------+
         |  0  1  2  3  4  5  6  7  8  9  a  b  c  d  e  f |
+--------+-------------------------------------------------+----------------+
|00000000| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000010| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000020| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000030| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000040| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000050| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000060| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000070| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000080| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
|00000090| 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f 10 |................|
+--------+-------------------------------------------------+----------------+
       服务端收到的数据，发现是一起接收到的，出现了黏包的问题
     */

    /*
        当客户端发送的字节数过多时，会发生半包现象
        即一整条的数据被分为多次接收
     */
    public static void test1() throws InterruptedException {
        NioEventLoopGroup worker=new NioEventLoopGroup(2);
        NioEventLoopGroup boss=new NioEventLoopGroup();
        ChannelFuture cf = new ServerBootstrap()
                .group(boss,worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        pipeline.addLast(new LoggingHandler(LogLevel.DEBUG));
                        pipeline.addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                System.out.println("connected"+ctx.channel());
                                super.channelActive(ctx);
                            }

                            @Override
                            public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                System.out.println("disconnected"+ctx.channel());
                                super.channelInactive(ctx);
                            }
                        });
                    }
                }).bind(8080);
        cf.sync();
        cf.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                boss.shutdownGracefully();
                worker.shutdownGracefully();
                System.out.println("shutdown gracefully!");
            }
        });
    }


    //通过预设定长度解决，黏包半包问题
    public static void test2() throws InterruptedException {
        NioEventLoopGroup worker=new NioEventLoopGroup(2);
        NioEventLoopGroup boss=new NioEventLoopGroup();
        ChannelFuture cf = new ServerBootstrap()
                .group(boss,worker)
                .channel(NioServerSocketChannel.class)
                .childHandler(new ChannelInitializer<NioSocketChannel>() {
                    @Override
                    protected void initChannel(NioSocketChannel ch) throws Exception {
                        ChannelPipeline pipeline = ch.pipeline();
                        //添加这个handler是关键
                        pipeline.addLast(new LengthFieldBasedFrameDecoder(1024,0,1,0,1));
                        pipeline.addLast(new LoggingHandler(LogLevel.DEBUG));
                        pipeline.addLast(new ChannelInboundHandlerAdapter(){
                            @Override
                            public void channelActive(ChannelHandlerContext ctx) throws Exception {
                                System.out.println("connected"+ctx.channel());
                                super.channelActive(ctx);
                            }

                            @Override
                            public void channelInactive(ChannelHandlerContext ctx) throws Exception {
                                System.out.println("disconnected"+ctx.channel());
                                super.channelInactive(ctx);
                            }
                        });
                    }
                }).bind(8080);
        cf.sync();
        cf.channel().closeFuture().addListener(new GenericFutureListener<Future<? super Void>>() {
            @Override
            public void operationComplete(Future<? super Void> future) throws Exception {
                boss.shutdownGracefully();
                worker.shutdownGracefully();
                System.out.println("shutdown gracefully!");
            }
        });
    }
}
